package org.geometerplus.zlibrary.ui.android.view;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewConfiguration;

import com.shwread.android.qysw.activity.ReadingBookActivity;
import com.shwread.android.qysw10000204.R;

import org.geometerplus.fbreader.fbreader.ActionCode;
import org.geometerplus.zlibrary.core.application.ZLApplication;
import org.geometerplus.zlibrary.core.view.ZLView;
import org.geometerplus.zlibrary.core.view.ZLViewWidget;
import org.geometerplus.zlibrary.text.view.ZLTextElementArea;
import org.geometerplus.zlibrary.text.view.ZLTextView;

import logic.util.logutil.LogUtil;


/**
 * 书本渲染页面
 */
public class LQReadingView extends View implements ZLViewWidget, View.OnLongClickListener {

    private final Paint myPaint = new Paint();
    private final BitmapManager myBitmapManager = new BitmapManager(this);
    private Bitmap myFooterBitmap;
    private Bitmap myHeaderBitmap;
    private ZLAndroidPaintContext myInitPaintContext = null;

    public LQReadingView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        init();
    }

    public LQReadingView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    public LQReadingView(Context context) {
        super(context);
        init();
    }

    private void init() {
        // next line prevent ignoring first onKeyDown DPad event
        // after any dialog was closed
        setFocusableInTouchMode(true);
        setDrawingCacheEnabled(false);
        setOnLongClickListener(this);
    }

    public ZLAndroidPaintContext getInitPaintContext() {
        final ZLView view = ZLApplication.Instance().getCurrentView();
        int scrollBarWidth = 0;
        if (view != null && view.isScrollbarShown()) {
            scrollBarWidth = getVerticalScrollbarWidth();
        }

        if (myInitPaintContext == null) {
            myInitPaintContext = new ZLAndroidPaintContext(new Canvas(), getWidth(), getMainAreaHeight(), scrollBarWidth);
            return myInitPaintContext;
        }

        int width = getWidth() - scrollBarWidth;
        myInitPaintContext.setMyWidth(width);
        myInitPaintContext.setMyHeight(getMainAreaHeight());
        return myInitPaintContext;
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        getAnimationProvider().terminate();
        if (myScreenIsTouched) {
            final ZLView view = ZLApplication.Instance().getCurrentView();
            myScreenIsTouched = false;
            view.onScrollingFinished(ZLView.PageIndex.current);
        }
    }

    @Override
    protected void onDraw(final Canvas canvas) {
        LogUtil.d("luhuhai", "onDraw");
        final Context context = getContext();
        if (context instanceof ReadingBookActivity) {
            ((ReadingBookActivity) context).createWakeLock();
        } else {
            System.err.println("A surprise: view's context is not an FBReader");
        }
        super.onDraw(canvas);

        //		final int w = getWidth();
        //		final int h = getMainAreaHeight();

        if (getAnimationProvider().inProgress()) {
            onDrawInScrolling(canvas);
        } else {
            onDrawStatic(canvas);
            ZLApplication.Instance().onRepaintFinished();
        }
    }

    private AnimationProvider myAnimationProvider;
    private ZLView.Animation myAnimationType;

    private AnimationProvider getAnimationProvider() {
        final ZLView.Animation type = ZLApplication.Instance().getCurrentView().getAnimationType();
        if (myAnimationProvider == null || myAnimationType != type) {
            myAnimationType = type;
            switch (type) {
                case none:
                    myAnimationProvider = new NoneAnimationProvider(myBitmapManager);
                    break;
                case curl:
                    myAnimationProvider = new CurlAnimationProvider(myBitmapManager);
                    break;
                case slide:
                    myAnimationProvider = new SlideAnimationProvider(myBitmapManager);
                    break;
                case shift:
                    myAnimationProvider = new ShiftAnimationProvider(myBitmapManager);
                    break;
            }
        }
        return myAnimationProvider;
    }

    private void onDrawInScrolling(Canvas canvas) {
        final ZLView view = ZLApplication.Instance().getCurrentView();

        //		final int w = getWidth();
        //		final int h = getMainAreaHeight();

        final AnimationProvider animator = getAnimationProvider();
        final AnimationProvider.Mode oldMode = animator.getMode();
        animator.doStep();
        if (animator.inProgress()) {
            animator.draw(canvas);
            if (animator.getMode().Auto) {
                postInvalidate();
            }
            drawFooter(canvas);
            drawHeader(canvas);
        } else {
            switch (oldMode) {
                case AnimatedScrollingForward: {
                    final ZLView.PageIndex index = animator.getPageToScrollTo();
                    myBitmapManager.shift(index == ZLView.PageIndex.next);
                    view.onScrollingFinished(index);
                    ZLApplication.Instance().onRepaintFinished();
                    break;
                }
                case AnimatedScrollingBackward:
                    view.onScrollingFinished(ZLView.PageIndex.current);
                    break;
            }
            onDrawStatic(canvas);
        }
    }

    @Override
    public void reset() {
        myBitmapManager.reset();
    }

    @Override
    public void repaint() {
        postInvalidate();
    }

    @Override
    public void startManualScrolling(int x, int y, ZLView.Direction direction) {
        final AnimationProvider animator = getAnimationProvider();
        animator.setup(direction, getWidth(), getMainAreaHeight());
        animator.startManualScrolling(x, y);
    }

    @Override
    public void scrollManuallyTo(int x, int y) {
        final ZLView view = ZLApplication.Instance().getCurrentView();
        final AnimationProvider animator = getAnimationProvider();
        if (view.canScroll(animator.getPageToScrollTo(x, y))) {
            animator.scrollTo(x, y);
            postInvalidate();
        }
    }

    @Override
    public void startAnimatedScrolling(ZLView.PageIndex pageIndex, int x, int y, ZLView.Direction direction, int speed) {
        final ZLView view = ZLApplication.Instance().getCurrentView();
        if (pageIndex == ZLView.PageIndex.current || !view.canScroll(pageIndex)) {
            if (System.currentTimeMillis() - tempTime < 5000) return;
            //#debug
            base.tina.core.log.LogPrinter.e("trun page", "startAnimatedScrolling  : " + pageIndex);
            ZLApplication.Instance().runAction(ActionCode.OPEN_ONLINE_BOOKS, pageIndex);
            tempTime = System.currentTimeMillis();
            return;
        }
        final AnimationProvider animator = getAnimationProvider();
        animator.setup(direction, getWidth(), getMainAreaHeight());
        animator.startAnimatedScrolling(pageIndex, x, y, speed);
        if (animator.getMode().Auto) {
            postInvalidate();
        }
    }

    @Override
    public void startAnimatedScrolling(ZLView.PageIndex pageIndex, ZLView.Direction direction, int speed) {

        final ZLView view = ZLApplication.Instance().getCurrentView();
        if (pageIndex == ZLView.PageIndex.current || !view.canScroll(pageIndex)) {
            if (System.currentTimeMillis() - tempTime < 5000) {
                return;
            }
            //#debug
            base.tina.core.log.LogPrinter.e("turn page", "!!!!!!!startAnimatedScrolling");
            ZLApplication.Instance().runAction(ActionCode.OPEN_ONLINE_BOOKS, pageIndex);
            tempTime = System.currentTimeMillis();
            return;
        }
        final AnimationProvider animator = getAnimationProvider();
        animator.setup(direction, getWidth(), getMainAreaHeight());
        animator.startAnimatedScrolling(pageIndex, null, null, speed);
        if (animator.getMode().Auto) {
            postInvalidate();
        }
    }

    long tempTime = 0;
    ZLView.PageIndex tempAnimated = ZLView.PageIndex.current;

    @Override
    public void startAnimatedScrolling(int x, int y, int speed) {

        final ZLView view = ZLApplication.Instance().getCurrentView();
        final AnimationProvider animator = getAnimationProvider();
        if (!view.canScroll(animator.getPageToScrollTo(x, y))) {
            if (System.currentTimeMillis() - tempTime < 5000 && tempAnimated == animator.getPageToScrollTo(x, y)) {
                return;
            }
            //#debug
            base.tina.core.log.LogPrinter.e("turn page", "startAnimatedScrolling2:" + animator.getPageToScrollTo(x, y));
            ZLApplication.Instance().runAction(ActionCode.OPEN_ONLINE_BOOKS, animator.getPageToScrollTo(x, y));
            tempTime = System.currentTimeMillis();
            tempAnimated = animator.getPageToScrollTo(x, y);
            animator.terminate();
            return;
        }
        animator.startAnimatedScrolling(x, y, speed);
        postInvalidate();
    }

    void drawOnBitmap(Bitmap bitmap, ZLView.PageIndex index) {
        final ZLView view = ZLApplication.Instance().getCurrentView();
        if (view == null) {
            return;
        }

        final ZLAndroidPaintContext context = new ZLAndroidPaintContext(new Canvas(bitmap), getWidth(), getMainAreaHeight(), view.isScrollbarShown() ? getVerticalScrollbarWidth() : 0);
        view.paint(context, index);

        //画上笔记的icon

        drawRemarkIcons(context, view, index);
    }

    private void drawRemarkIcons(ZLAndroidPaintContext context, ZLView view, ZLView.PageIndex index) {
        //画上笔记的icon
        for (ZLTextElementArea area : ((ZLTextView) view).getRemarkIconZLTextElementAreas(index)) {
            if (area != null) {
                Bitmap remarkIcon = BitmapFactory.decodeResource(getContext().getResources(), R.drawable.note_tag);
                ICON_HEIGHT = remarkIcon.getHeight();
                ICON_WIDTH = remarkIcon.getWidth();
                context.drawRemarkIcon(remarkIcon, area.XEnd, area.YEnd);
            }
        }
    }

    public static int ICON_HEIGHT;
    public static int ICON_WIDTH;

    private void drawHeader(Canvas canvas) {
        final ZLView view = ZLApplication.Instance().getCurrentView();
        final ZLView.HeaderArea header = view.getHeaderArea();
        if (header == null) {
            myHeaderBitmap = null;
            return;
        }

        if (myHeaderBitmap != null && (myHeaderBitmap.getWidth() != getWidth() || myHeaderBitmap.getHeight() != header.getHeight())) {
            myHeaderBitmap = null;
        }
        if (myHeaderBitmap == null) {
            myHeaderBitmap = Bitmap.createBitmap(getWidth(), header.getHeight(), Bitmap.Config.RGB_565);
        }
        final ZLAndroidPaintContext context = new ZLAndroidPaintContext(new Canvas(myHeaderBitmap), getWidth(), header.getHeight(), view.isScrollbarShown() ? getVerticalScrollbarWidth() : 0);
        header.paint(context);
        canvas.drawBitmap(myHeaderBitmap, 0, 0, myPaint);
    }

    private void drawFooter(Canvas canvas) {
        final ZLView view = ZLApplication.Instance().getCurrentView();
        final ZLView.FooterArea footer = view.getFooterArea();

        if (footer == null) {
            myFooterBitmap = null;
            return;
        }

        if (myFooterBitmap != null && (myFooterBitmap.getWidth() != getWidth() || myFooterBitmap.getHeight() != footer.getHeight())) {
            myFooterBitmap = null;
        }
        if (myFooterBitmap == null) {
            myFooterBitmap = Bitmap.createBitmap(getWidth(), footer.getHeight(), Bitmap.Config.RGB_565);
        }
        final ZLAndroidPaintContext context = new ZLAndroidPaintContext(new Canvas(myFooterBitmap), getWidth(), footer.getHeight(), view.isScrollbarShown() ? getVerticalScrollbarWidth() : 0);
        footer.paint(context);
        canvas.drawBitmap(myFooterBitmap, 0, getHeight() - footer.getHeight(), myPaint);
    }

    private void onDrawStatic(final Canvas canvas) {
        myBitmapManager.setSize(getWidth(), getMainAreaHeight());
        Bitmap bmp = myBitmapManager.getBitmap(ZLView.PageIndex.current);
        canvas.drawBitmap(bmp, 0, getHeaderAreaHeight(), myPaint);
        drawFooter(canvas);
        drawHeader(canvas);
    }

    @Override
    public boolean onTrackballEvent(MotionEvent event) {
        if (event.getAction() == MotionEvent.ACTION_DOWN) {
            onKeyDown(KeyEvent.KEYCODE_DPAD_CENTER, null);
        } else {
            ZLApplication.Instance().getCurrentView().onTrackballRotated((int) (10 * event.getX()), (int) (10 * event.getY()));
        }
        return true;
    }

    private class LongClickRunnable implements Runnable {
        @Override
        public void run() {
            if (performLongClick()) {
                myLongClickPerformed = true;
            }
        }
    }

    private volatile LongClickRunnable myPendingLongClickRunnable;
    private volatile boolean myLongClickPerformed;

    private void postLongClickRunnable() {
        myLongClickPerformed = false;
        myPendingPress = false;
        if (myPendingLongClickRunnable == null) {
            myPendingLongClickRunnable = new LongClickRunnable();
        }
        postDelayed(myPendingLongClickRunnable, 2 * ViewConfiguration.getLongPressTimeout());
    }

    private class ShortClickRunnable implements Runnable {
        @Override
        public void run() {
            final ZLView view = ZLApplication.Instance().getCurrentView();
            view.onFingerSingleTap(myPressedX, myPressedY);
            myPendingPress = false;
            myPendingShortClickRunnable = null;
        }
    }

    private volatile ShortClickRunnable myPendingShortClickRunnable;

    private volatile boolean myPendingPress;
    private volatile boolean myPendingDoubleTap;
    private int myPressedX, myPressedY;
    private boolean myScreenIsTouched;

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        int x = (int) event.getX();
        int y = (int) event.getY();

        final ZLView view = ZLApplication.Instance().getCurrentView();
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                if (myPendingShortClickRunnable != null) {
                    removeCallbacks(myPendingShortClickRunnable);
                    myPendingShortClickRunnable = null;
                    myPendingDoubleTap = true;
                } else {
                    postLongClickRunnable();
                    myPendingPress = true;
                }
                myScreenIsTouched = true;
                myPressedX = x;
                myPressedY = y;
                break;
            case MotionEvent.ACTION_UP:
                if (myPendingDoubleTap) {
                    view.onFingerDoubleTap(x, y);
                } else if (myLongClickPerformed) {
                    view.onFingerReleaseAfterLongPress(x, y);
                } else {
                    if (myPendingLongClickRunnable != null) {
                        removeCallbacks(myPendingLongClickRunnable);
                        myPendingLongClickRunnable = null;
                    }
                    if (myPendingPress) {
                        if (view.isDoubleTapSupported()) {
                            if (myPendingShortClickRunnable == null) {
                                myPendingShortClickRunnable = new ShortClickRunnable();
                            }
                            postDelayed(myPendingShortClickRunnable, ViewConfiguration.getDoubleTapTimeout());
                        } else {
                            view.onFingerSingleTap(x, y);
                        }
                    } else {
                        view.onFingerRelease(x, y);
                    }
                }
                myPendingDoubleTap = false;
                myPendingPress = false;
                myScreenIsTouched = false;
                break;
            case MotionEvent.ACTION_MOVE: {
                final int slop = ViewConfiguration.get(getContext()).getScaledTouchSlop();
                final boolean isAMove = Math.abs(myPressedX - x) > slop || Math.abs(myPressedY - y) > slop;
                if (isAMove) {
                    myPendingDoubleTap = false;
                }
                if (myLongClickPerformed) {
                    view.onFingerMoveAfterLongPress(x, y);
                } else {
                    if (myPendingPress) {
                        if (isAMove) {
                            if (myPendingShortClickRunnable != null) {
                                removeCallbacks(myPendingShortClickRunnable);
                                myPendingShortClickRunnable = null;
                            }
                            if (myPendingLongClickRunnable != null) {
                                removeCallbacks(myPendingLongClickRunnable);
                            }
                            view.onFingerPress(myPressedX, myPressedY);
                            myPendingPress = false;
                        }
                    }
                    if (!myPendingPress) {
                        view.onFingerMove(x, y);
                    }
                }
                break;
            }
        }
        return true;
    }

    @Override
    public boolean onLongClick(View v) {
        final ZLView view = ZLApplication.Instance().getCurrentView();
        return view.onFingerLongPress(myPressedX, myPressedY);
    }

    @Override
    protected int computeVerticalScrollExtent() {
        final ZLView view = ZLApplication.Instance().getCurrentView();
        if (!view.isScrollbarShown()) {
            return 0;
        }
        final AnimationProvider animator = getAnimationProvider();
        if (animator.inProgress()) {
            final int from = view.getScrollbarThumbLength(ZLView.PageIndex.current);
            final int to = view.getScrollbarThumbLength(animator.getPageToScrollTo());
            final int percent = animator.getScrolledPercent();
            return (from * (100 - percent) + to * percent) / 100;
        } else {
            return view.getScrollbarThumbLength(ZLView.PageIndex.current);
        }
    }

    @Override
    protected int computeVerticalScrollOffset() {
        final ZLView view = ZLApplication.Instance().getCurrentView();
        if (!view.isScrollbarShown()) {
            return 0;
        }
        final AnimationProvider animator = getAnimationProvider();
        if (animator.inProgress()) {
            final int from = view.getScrollbarThumbPosition(ZLView.PageIndex.current);
            final int to = view.getScrollbarThumbPosition(animator.getPageToScrollTo());
            final int percent = animator.getScrolledPercent();
            return (from * (100 - percent) + to * percent) / 100;
        } else {
            return view.getScrollbarThumbPosition(ZLView.PageIndex.current);
        }
    }

    @Override
    protected int computeVerticalScrollRange() {
        final ZLView view = ZLApplication.Instance().getCurrentView();
        if (!view.isScrollbarShown()) {
            return 0;
        }
        return view.getScrollbarFullSize();
    }

    private int getMainAreaHeight() {
        final ZLView.FooterArea footer = ZLApplication.Instance().getCurrentView().getFooterArea();
        return footer != null ? getHeight() - getHeaderAreaHeight() - footer.getHeight() : getHeight();
    }

    private int getHeaderAreaHeight() {
        final ZLView.HeaderArea header = ZLApplication.Instance().getCurrentView().getHeaderArea();
        return header != null ? header.getHeight() : 0;
    }
}
